#include "stdlib.hpp"
#include <purewell/filestatus.hpp>

namespace purewell
{

#define _xchg(x) ((struct stat*)(x))
#define _cxchg(x) ((const struct stat*)(x))
#define _imp_isXXX(name,flag) bool\
	PWFileStatus::is##name (void) const\
	{ return 0 != ((((const struct stat*)m_pData)->st_mode) & (flag)); }

bool
PWFileStatus::isSocket(void) const
{
#if defined(S_ISSOCK)
	return 0 != S_ISSOCK(_cxchg(m_pData)->st_mode);
#else
	return false;
#endif
}

bool
PWFileStatus::isRegularFile(void) const
{
#if defined(S_ISREG)
	return 0 != S_ISREG(_cxchg(m_pData)->st_mode);
#elif defined(S_IFREG)
	return S_IFREG == ((S_IFMT&_cxchg(m_pData)->st_mode) & S_IFREG);
#else
	return false;
#endif
}

bool
PWFileStatus::isDirectory(void) const
{
#if defined(S_ISDIR)
	return 0 != S_ISDIR(_cxchg(m_pData)->st_mode);
#else
	return false;
#endif
}

bool
PWFileStatus::isCharacterDevice(void) const
{
#if defined(S_ISCHR)
	return 0 != S_ISCHR(_cxchg(m_pData)->st_mode);
#elif defined(S_IFCHR)
	return S_IFCHR == ((S_IFMT&_cxchg(m_pData)->st_mode) & S_IFCHR);
#elif defined(_S_IFCHR)
	return 0 != _S_IFCHR(_cxchg(m_pData)->st_mode);
#endif
}

bool
PWFileStatus::isBlockDevice(void) const
{
#if defined(S_ISBLK)
	return 0 != S_ISBLK(_cxchg(m_pData)->st_mode);
#else
	return false;
#endif
}

bool
PWFileStatus::isFIFO(void) const
{
#if defined(S_ISFIFO)
	return 0 != S_ISFIFO(_cxchg(m_pData)->st_mode);
#else
	return false;
#endif
}

bool
PWFileStatus::isSymbolicLink(void) const
{
#if defined(S_ISLINK)
	return 0 != S_ISLNK(_cxchg(m_pData)->st_mode);
#else
	return false;
#endif
}

PWFileStatus::PWFileStatus()
{
	memset(m_pData, 0x00, sizeof(struct stat));
}

PWFileStatus::PWFileStatus(const PWFileStatus& stat)
{
	memcpy(m_pData, stat.m_pData, sizeof(struct stat));
}

PWFileStatus::PWFileStatus(const PWFile& file)
{
	getStatus(file);
}

PWFileStatus::PWFileStatus(int fd)
{
	getStatus(fd);
}

PWFileStatus::~PWFileStatus()
{
}

PWFileStatus&
PWFileStatus::operator = (const PWFileStatus& value)
{
	struct stat* pstat((struct stat*)m_pData);
	memcpy(pstat, value.m_pData, sizeof(struct stat));
	return *this;
}

PWFileStatus&
PWFileStatus::operator = (const PWFile& file)
{
	struct stat* pstat((struct stat*)m_pData);
	fstat(file.getHandle(), pstat);
	return *this;
}

PWFileStatus&
PWFileStatus::operator = (int fd)
{
	struct stat* pstat((struct stat*)m_pData);
	fstat(fd, pstat);
	return *this;
}

bool
PWFileStatus::getStatus(const PWFile& file)
{
	struct stat* pstat((struct stat*)m_pData);
	return 0 == fstat(file.getHandle(), pstat);
}

bool
PWFileStatus::getStatus(int fd)
{
	struct stat* pstat((struct stat*)m_pData);
	return 0 == fstat(fd, pstat);
}

bool
PWFileStatus::getStatus(const char* path)
{
	struct stat* pstat((struct stat*)m_pData);
	return 0 == stat(path, pstat);
}

bool
PWFileStatus::getStatus2(const char* path)
{
#ifdef __PW_HAVE_LSTAT
	struct stat* pstat((struct stat*)m_pData);
	return 0 == lstat(path, pstat);
#else
	return false;
#endif
}

dev_t
PWFileStatus::getDevice(void) const
{
	return _cxchg(m_pData)->st_dev;
}

ino_t   
PWFileStatus::getINode(void) const
{
	return _cxchg(m_pData)->st_ino;
}

mode_t  
PWFileStatus::getMode(void) const
{
	return _cxchg(m_pData)->st_mode;
}

nlink_t 
PWFileStatus::getHardLinkCount(void) const
{
	return _cxchg(m_pData)->st_nlink;
}

uid_t   
PWFileStatus::getUID(void) const
{
	return _cxchg(m_pData)->st_uid;
}

gid_t   
PWFileStatus::getGID(void) const
{
	return _cxchg(m_pData)->st_gid;
}

dev_t   
PWFileStatus::getRDevice(void) const
{
	return _cxchg(m_pData)->st_rdev;
}

off_t   
PWFileStatus::getSize(void) const
{
	return _cxchg(m_pData)->st_size;
}

blksize_t       
PWFileStatus::getBlockSize(void) const
{
#ifdef __PW_HAVE_MEM_STAT_ST_BLKSIZE
	return _cxchg(m_pData)->st_blksize;
#else
	return 0;
#endif//!__PW_HAVE_MEM_STAT_ST_BLKSIZE
}

blkcnt_t        
PWFileStatus::getBlockCount(void) const
{
#ifdef __PW_HAVE_MEM_STAT_ST_BLOCKS
	return _cxchg(m_pData)->st_blocks;
#else
	return 0;
#endif//!__PW_HAVE_MEM_STAT_ST_BLOCKS
}

time_t  
PWFileStatus::getAccessTime(void) const
{
	return _cxchg(m_pData)->st_atime;
}

time_t  
PWFileStatus::getModificationTime(void) const
{
	return _cxchg(m_pData)->st_mtime;
}

time_t  
PWFileStatus::getChangeTime(void) const
{
	return _cxchg(m_pData)->st_ctime;
}

};//namespace purewell


